<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8">
    <title>Hello world</title>
    <style>
        * {
    margin: 0;
    padding: 0;
  }

  .box {
    position: fixed;
    top: 50%;
    left: 50%;
    margin-top: -40vh;
    margin-left: -40vw;
    width: 80vw;
    height: 80vh;
  }

  .edit-wrapper {
    position: absolute;
    top: 0;
    left: 0;
    z-index: -10;
    opacity: 0;
    /*z-index: 10;
    opacity: 1;*/
    width: 100%;
    height: 100%;
    background: #000;
    overflow: hidden;
  }

  .edit-wrapper.is-show {
    z-index: 10;
    opacity: 1;
  }

  .edit-content {
    position: absolute;
    z-index: 10;
    opacity: 1;
    top: 50%;
    left: 50%;
    transform-origin: center;
  }

  .aa {
    width: 100%;
    height: 100%;
    opacity: 1;
  }
  .btn-box {
    position: fixed;
    top: 40px;
    left: 40px;
    z-index: 10;
  }

  .right-menu {
    display: none;
    position: fixed;
    top: 0;
    left: 0;
    z-index: 1000;
    background: #fff;
    border-radius: 6px;
    padding: 6px 0;
    border: 1px solid #DCDFE6;
  }
  .right-menu.del .item {
    padding: 0 20px;
    line-height: 34px;
    cursor: pointer;
    min-width: 100px;
  }
  .right-menu.del .item:hover {
    background: #F5F7FA;
  }
  .right-menu.add .title {
    font-size: 16px;
    padding-left: 10px;
    color: #000;
    font-weight: bold;
    text-align: left;
}
.right-menu.add .list {
    max-width: 400px;
    padding: 10px 0 0 10px;
}
.right-menu.add .list:after {
    content: '';
    display: block;
    clear: both;
}
.right-menu.add .list .item {
    float: left;
    margin: 0 10px 10px 0;
    padding: 0 6px;
    line-height: 26px;
    cursor: pointer;
    border: 1px solid currentColor;
    border-radius: 4px;
}
.right-menu.add .list .item:hover {
    font-weight: bold;
}
.right-menu.add .new {
    display: flex;
    pag: 10px;
    padding: 0 10px;
}
  </style>
</head>

<body>
    <div class="btn-box">
        <button onclick="showEditClick()">显示</button>
        <button onclick="hideEdit()">隐藏</button>
    </div>
    <div class="box">
        <div class="aa"></div>
        <div class="edit-wrapper">
            <div class="edit-content">
                <div style="width:100%; height:100%;" class="imageContainer"></div>
            </div>
        </div>
    </div>
    <div class="right-menu del">
        <div class="item">删除</div>
    </div>
    <div class="right-menu add">
        <div class="title">添加</div>
        <div class="list"></div>
        <div class="new">
            <input type="text" placeholder="自定义类型" />
            <button class="btn">确定</button>
        </div>
    </div>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
    <script src="./static/hammer.js"></script>
    <script src="./static/cornerstone.min.js"></script>
    <script src="./static/cornerstoneMath.min.js"></script>
    <script src="./static/cornerstoneWADOImageLoader.min.js"></script>
    <script src="./static/cornerstoneWebImageLoader.min.js"></script>
    <script src="./static/cornerstoneTools.min.js"></script>
    <script src="./static/dicomParser.min.js"></script>
    <script src="./static/addMouseWheel.js"></script>
    <script>
    const baseUrl = "http://127.0.0.1:8000/static/js/";
    const image_uir = '111'

    var config = {
        "胸膜增厚": "rgb(255, 0, 255)",
        "纤维灶": "rgb(220, 20, 60)",
        "钙化": "rgb(148, 0, 211)",
        "骨折": "rgb(123, 104, 238)",
        "肺不张": "rgb(0, 0, 205)",
        "肿块": "rgb(30, 144, 255)",
        "结节": "rgb(184, 134, 11)",
        "肺气肿": "rgb(0, 139, 0)",
        "气胸": "rgb(139, 35, 35)",
        "PICC": "rgb(218, 165, 32)",
        "积液": "rgb(255, 140, 0)",
        "积气": "rgb(0, 0, 0)",
        "实变": "rgb(85, 107, 47)",
        "术后金属": "rgb(95, 158, 160)",
        "膈下游离气体": "rgb(9,113,175)",
        "肠道积气扩张": "rgb(4,248,194)",
        "肠道积液液平": "rgb(148, 0, 211)",
        "泌尿系统结石": "rgb(108,227,33)"
    }



    var infos = {
        '111_ctr': {
            center_x: 1277,
            heart_x_begin_left: 936,
            heart_x_end_right: 2100,
            heart_y_begin_left: 1531,
            heart_y_end_right: 1621,
            lung_x_begin: 170,
            lung_x_end: 2348,
            lung_y: 1565,
            ratio: 0.5344,
        },
        '111_current': [{
            "name": "纤维灶",
            mark: true,
            "confidence": 1.0,
            "xmin": 1791.5301292590002,
            "ymin": 1144.1843983500526,
            "xmax": 2205.530129259,
            "ymax": 1429.1843983500526
        }, {
            "name": "结节",
            mark: true,
            "confidence": 1.0,
            "xmin": 1685.046367851623,
            "ymin": 668.259659969088,
            "xmax": 1751.046367851623,
            "ymax": 733.259659969088
        }, {
            "name": "实变",
            mark: true,
            "confidence": 1.0,
            "xmin": 1211.2967542503864,
            "ymin": 895.5332302936631,
            "xmax": 1613.2967542503864,
            "ymax": 1159.533230293663
        }, {
            "name": "结节",
            mark: true,
            "confidence": 1.0,
            "xmin": 902.8114374034003,
            "ymin": 814.0710973724885,
            "xmax": 1049.8114374034003,
            "ymax": 964.0710973724885
        }]
    }

    window.onload = function() {
        _initCornerstone();

        aaInitCornerstone();


        // 隐藏右键菜单
        $(window).on('click', () => {
            $('.right-menu').hide();
        })

        setDownList();

        // 绑定删除事件
        $('.right-menu.del').on('click', '.item', () => {
            oEdit.deleteRectData();
        })
        // 绑定页面按下Delete事件
        window.addEventListener('keyup', (e) => {
            if(e.keyCode == 46 && oEdit.visible == true && oEdit.editRectIndex != -1) {
                oEdit.deleteIndex = oEdit.editRectIndex;
                oEdit.deleteRectData();
            }
        })
    }

    function _initCornerstone() {
        cornerstoneWADOImageLoader.external.cornerstone = cornerstone;
        cornerstoneWADOImageLoader.external.dicomParser = dicomParser;
        cornerstoneTools.external.cornerstoneMath = cornerstoneMath;
        cornerstoneTools.external.cornerstone = cornerstone;
        cornerstoneTools.external.Hammer = Hammer;

        // Image Loader
        const config = {
            webWorkerPath: `${baseUrl}assets/image-loader/cornerstoneWADOImageLoaderWebWorker.js`,
            taskConfiguration: {
                decodeTask: {
                    codecsPath: `${baseUrl}assets/image-loader/cornerstoneWADOImageLoaderCodecs.js`,
                },
            },
        };
        cornerstoneWADOImageLoader.webWorkerManager.initialize(config);
    }

    // 初始化影像
    function aaInitCornerstone() {
        let element = document.querySelector('.aa');
        cornerstone.enable(element);
        cornerstone.loadAndCacheImage('wadouri:http://localhost:8001/static/data/1.2.840.1.19439.0.1000.20220101135814.1480.10000.3383824/1.2.840.113564.12312312366.2022010113510529628.1003000225002').then(function(image) {

            var viewport = cornerstone.getDefaultViewportForImage(element, image);
            cornerstone.displayImage(element, image, viewport);
        });
        element.addEventListener('cornerstoneimagerendered', onImageRendered);
    }

    function onImageRendered(e) {
        oEdit.init(e);
    }

    // 设置下拉框
    function setDownList() {
        let html = '';
        for (let key in config) {
            html += `<div class="item" data-key="${key}" style="color:${config[key]}">${key}</div>`;
        }
        $('.right-menu.add .list').html(html);
        $('.right-menu.add .list').on('click', '.item', function() {
            let key = this.dataset.key;
            oEdit.addRect(key);
        })
        $('.right-menu.add .new').on('click', function(e) {
            e.stopPropagation();
        })
        $('.right-menu.add .new').on('click', '.btn', function(e) {
            let key = $('.right-menu.add .new input').val();
            oEdit.addRect(key);
            $('.right-menu.add').hide();
        })
    }

    // 显示编辑线
    function showEditClick() {
        oEdit.show({
            data: {
                line: infos[image_uir + '_ctr'],
                rect: infos[image_uir + '_current']
            },
            showLine: true
        });
    }


    // 隐藏
    function hideEdit() {
        oEdit.close();
    }


    const oEdit = {
        visible: false,

        oWrapper: $('.edit-wrapper'),
        oPosition: $('.edit-wrapper .edit-position'),
        oContent: $('.edit-wrapper .edit-content'),
        oContainer: $('.edit-wrapper .imageContainer'),
        oTarget: null,
        oCanvas: null,
        context: null,

        // 是否添加矩形
        isAddRect: false,
        editRectIndex: -1,
        add: {
            name: '',
            top: 0,
            left: 0,
            downx: 0,
            downy: 0,
            xmin: 0,
            ymin: 0,
            xmax: 0,
            ymax: 0,
        },

        // 删除下标
        deleteIndex: -1,

        // 图片数据
        image: {
            ratio: 0,
            leftDis: 0,
            topDis: 0,
            width: 0,
            height: 0,
            file: null
        },
        // 编辑类型，line线，rect方框
        editType: '',
        // 数据
        oldData: null,
        newData: null,
        startData: null,
        // 路径
        paths: [],
        oPath: null,
        // 滚动
        scale: 1,
        // 显示
        show(options) {
            // 判断是否重置图片位置
            if(options.reloadPosition !== false) {
                this.setImagePosition();
            }

            this.showLine = options.showLine; // 是否显示线
            this.oldData = JSON.parse(JSON.stringify(options.data));
            this.newData = JSON.parse(JSON.stringify(options.data));

            // 设置初始编辑为-1
            this.editRectIndex = ('editRectIndex' in options) ? options.editRectIndex : -1;

            this.drawData();

            this.oWrapper.addClass('is-show');
            this.visible = true;
        },
        // 关闭
        close() {
            this.oWrapper.removeClass('is-show');
            this.visible = false;
        },
        // 初始化
        async init(e) {
            await this.initImageData(e);
            await waitTimeout(50);

            this.initEvent();
        },
        // 画
        addRect(name) {
            this.oWrapper.addClass('is-show');

            this.isAddRect = true;
            this.add.name = name;
            // 绘图
            this.drawData(true);
            this.visible = true;
        },
        initEvent() {
            // 缩放大小
            addMouseWheel(this.oWrapper[0], (delta) => {
                let scale = this.scale;
                if (delta > 0) {
                    scale += 0.05;
                } else if (delta < 0) {
                    scale -= 0.05;
                }
                if (scale >= 2) {
                    scale = 2;
                }
                if (scale <= this.image.ratio) {
                    scale = this.image.ratio;
                }
                this.scale = scale;
                this.oContent.css({
                    transform: `translate(-50%, -50%) scale(${scale})`
                })
            })

            // 拖动
            let cIsDown = false;
            let cdownx = 0,
                cdowny = 0;
            let startLeft = 0,
                startTop = 0;
            this.oWrapper.on('mousedown', (e) => {
                if (isDown) {
                    return;
                }
                cIsDown = true;
                cdownx = e.pageX;
                cdowny = e.pageY;
                startLeft = parseInt(this.oContent.css('left'));
                startTop = parseInt(this.oContent.css('top'));
            })

            window.addEventListener('mousemove', (e) => {
                if (cIsDown) {
                    var movex = e.pageX - cdownx + startLeft;
                    var movey = e.pageY - cdowny + startTop;
                    this.oContent.css({
                        left: movex + 'px',
                        top: movey + 'px'
                    })
                }
            })


            var context = this.context;
            var isDown = false;
            var downx = 0,
                downy = 0;

            // 点击选中编辑方框
            $(this.oCanvas).on('click', (e) => {
                if (!this.visible || isDown) {
                    return;
                }
                var canvas = this.oCanvas;
                var rect = canvas.getBoundingClientRect();
                var x = (e.clientX - rect.left) / this.scale;
                var y = (e.clientY - rect.top) / this.scale;
                this.paths.forEach((item) => {
                    if (context.isPointInPath(item.path, x, y)) {
                        if (item.cursor == 'pointer') {
                            // 设置编辑框下标
                            this.editRectIndex = item.index;
                            // 画数据
                            this.drawData();
                        }
                    }
                })
            })


            $(this.oCanvas).on('mousedown', (e) => {
                if (!this.visible) {
                    return;
                }
                var canvas = this.oCanvas;
                var rect = canvas.getBoundingClientRect();
                var x = (e.clientX - rect.left) / this.scale;
                var y = (e.clientY - rect.top) / this.scale;
                if (this.isAddRect) {
                    isDown = true;
                    this.add.left = rect.left;
                    this.add.top = rect.top;
                    this.add.downx = e.pageX;
                    this.add.downy = e.pageY;
                } else {
                    this.paths.forEach((item) => {
                        if (item.cursor != 'pointer') {
                            if (context.isPointInPath(item.path, x, y)) {
                                this.oPath = item;
                                isDown = true;
                                this.startData = JSON.parse(JSON.stringify(this.newData));
                                downx = e.pageX;
                                downy = e.pageY;
                            }
                        }
                    })
                }
            })

            $(this.oCanvas).on('mousemove', (e) => {
                if (!this.visible) {
                    return;
                }
                if (this.isAddRect && isDown) {
                    let movex = (e.pageX - this.add.downx) / this.scale;
                    let movey = (e.pageY - this.add.downy) / this.scale;
                    this.add.xmin = (this.add.downx - this.add.left) / this.scale;
                    this.add.ymin = (this.add.downy - this.add.top) / this.scale;
                    this.add.xmax = (this.add.downx - this.add.left) / this.scale + movex;
                    this.add.ymax = (this.add.downy - this.add.top) / this.scale + movey;
                    this.drawData(true);
                    this.drawAddRect();
                } else {
                    // 如果当前是按下
                    if (isDown) {
                        var movex = (e.pageX - downx) / this.scale;
                        var movey = (e.pageY - downy) / this.scale;
                        if (this.oPath.type == 'line') {
                            this.saveLineData(this.oPath.key, this.oPath.dir, movex, movey);
                        } else if (this.oPath.type == 'rect') {
                            this.saveRectData(this.oPath, movex, movey);
                        }
                    } else { // 非按下，移动改变canvas鼠标形状
                        var canvas = this.oCanvas;
                        var rect = canvas.getBoundingClientRect();
                        var x = (e.clientX - rect.left) / this.scale;
                        var y = (e.clientY - rect.top) / this.scale;
                        for (var i = 0; i < this.paths.length; i++) {
                            var item = this.paths[i];
                            if (context.isPointInPath(item.path, x, y)) {
                                canvas.style.cursor = item.cursor;
                                break;
                            } else {
                                canvas.style.cursor = '';
                            }
                        }
                    }
                }
            })

            window.addEventListener('mouseup', () => {
                if (!this.visible) {
                    return;
                }
                cIsDown = false;
                isDown = false;
                // 如果是添加矩形，鼠标抬起后，绘制可拖拽数据
                if (this.isAddRect) {
                    // 添加数据
                    this.newData.rect.push({
                        name: this.add.name,
                        mark: true,
                        confidence: 1.0,
                        xmin: (this.add.xmin - this.image.leftDis),
                        ymin: (this.add.ymin - this.image.topDis),
                        xmax: (this.add.xmax - this.image.leftDis),
                        ymax: (this.add.ymax - this.image.topDis),
                    })
                    // 画图形
                    this.isAddRect = false;
                    oEdit.show({
                        data: this.newData,
                        showLine: true,
                        editRectIndex: this.newData.rect.length - 1,
                        reloadPosition: false, // 设置不更新图像定位
                    });
                }
            })

            // 右键弹出菜单
            this.oWrapper.on('contextmenu', 'canvas', (e) => {
                e.preventDefault();
                e.stopPropagation();
                var canvas = this.oCanvas;
                var rect = canvas.getBoundingClientRect();
                var x = (e.clientX - rect.left) / this.scale;
                var y = (e.clientY - rect.top) / this.scale;
                let i = -1;
                this.paths.forEach((item) => {
                    if (context.isPointInPath(item.path, x, y)) {
                        if (item.cursor == 'move' || item.cursor == 'pointer') {
                            i = item.index;
                        }
                    }
                })
                $('.right-menu').hide();
                if (i == -1) {
                    $('.right-menu.add').css({
                        top: e.pageY + 'px',
                        left: e.pageX + 'px'
                    })
                    $('.right-menu.add').show();
                } else {
                    $('.right-menu.del').css({
                        top: e.pageY + 'px',
                        left: e.pageX + 'px'
                    })
                    $('.right-menu.del').show();
                    this.deleteIndex = i;
                }
            })
        },

        // 初始化图片宽高
        async initImageData(e) {
            var image = e.detail.image;

            // 保存图片宽高
            this.image.width = e.detail.image.width;
            this.image.height = e.detail.image.height;

            this.oTarget = e.target;
            this.image.ratio = e.detail.viewport.scale;

            this.setImagePosition();

            // 设置图片
            cornerstone.enable(this.oContainer[0]);
            var viewport = cornerstone.getDefaultViewportForImage(this.oContainer[0], image);
            cornerstone.displayImage(this.oContainer[0], image, viewport);
            await waitTimeout(50);

            // 获取ctx对象
            this.oCanvas = this.oContainer[0].children[0];
            this.context = this.oCanvas.getContext('2d');
            // 保存图片
            var base64 = this.oCanvas.toDataURL('image/png');
            var img = new Image();
            img.src = base64;
            img.onload = () => {
                this.image.file = img;
                this.image.leftDis = (img.width - this.image.width) / 2;
                this.image.topDis = (img.height - this.image.height) / 2;
            }
        },

        // 设置图片大小位置
        setImagePosition() {
            let ratio = this.image.ratio;
            // 设置宽高
            this.oContent.width(this.oTarget.clientWidth / ratio);
            this.oContent.height(this.oTarget.clientHeight / ratio);
            // 设置比例
            this.oContent.css({
                transform: `translate(-50%, -50%) scale(${ratio})`,
                left: '50%',
                top: '50%'
            })
            // 设置缩放大小
            this.scale = ratio;
        },

        // 保存线数据
        saveLineData(key, dir, movex, movey) {
            let oLine = this.newData.line;
            let startLine = this.startData.line;
            // 保存线位置数据
            oLine[key] = (dir == 'x' ? movex : movey) + startLine[key];
            // 计算心胸比
            oLine.ratio = (oLine.heart_x_end_right - oLine.heart_x_begin_left) / (oLine.lung_x_end - oLine.lung_x_begin);

            // 画数据
            this.drawData();
        },

        // 保存矩形数据
        saveRectData(path, movex, movey) {
            let oRect = this.newData.rect;
            let startRect = this.startData.rect;
            var index = path.index;
            if (path.dir == 'xy') {
                if (path.key instanceof Array) {
                    let xkey = path.key[0],
                        ykey = path.key[1];
                    oRect[index][xkey] = movex + startRect[index][xkey];
                    oRect[index][ykey] = movey + startRect[index][ykey];
                } else {
                    oRect[index].xmin = movex + startRect[index].xmin;
                    oRect[index].xmax = movex + startRect[index].xmax;
                    oRect[index].ymin = movey + startRect[index].ymin;
                    oRect[index].ymax = movey + startRect[index].ymax;
                }
            } else {
                oRect[index][path.key] = (path.dir == 'x' ? movex : movey) + startRect[index][path.key];
            }

            // 画数据
            this.drawData();
        },

        // 删除数据
        deleteRectData() {
            this.newData.rect[this.deleteIndex].isDelete = true;
            this.drawData();
        },

        // 画数据
        drawData(onlyImg) {
            this.paths = [];
            // 清空画布
            this.oCanvas.width = this.oCanvas.width;
            // 绘制底图
            this.drawImage();
            // 画线，画框
            this.drawRect(this.newData.rect, onlyImg);
            if (this.showLine) {
                this.drawLine(this.newData.line, onlyImg);
            }
        },

        // 绘制底图
        drawImage() {
            this.context.drawImage(this.image.file, 0, 0);
        },

        // 画线
        drawLine(data, onlyImg) {
            var ctr = {
                lung_x_begin: data.lung_x_begin + this.image.leftDis,
                lung_x_end: data.lung_x_end + this.image.leftDis,
                lung_y: data.lung_y + this.image.topDis,
                heart_x_begin_left: data.heart_x_begin_left + this.image.leftDis,
                heart_x_end_right: data.heart_x_end_right + this.image.leftDis,
                heart_y_begin_left: data.heart_y_begin_left + this.image.topDis,
                heart_y_end_right: data.heart_y_end_right + this.image.topDis,
            };
            var context = this.context;
            var paths = [];

            var path = null;

            let size1 = 6;
            let size2 = 20;
            let size3 = 6;
            let size4 = 50;

            context.beginPath();
            context.lineWidth = size1;
            context.strokeStyle = "green"
            context.moveTo(ctr.lung_x_begin, ctr.lung_y);
            context.lineTo(ctr.lung_x_end, ctr.lung_y);
            context.closePath();
            context.stroke();

            centerX = (ctr.lung_x_begin + ctr.lung_x_end) / 2
            Y = [ctr.lung_y, ctr.heart_y_begin_left, ctr.heart_y_end_right]
            minY = Math.min(...Y)
            maxY = Math.max(...Y)
            context.strokeStyle = "black"
            context.beginPath();
            context.moveTo(centerX, minY - size4);
            context.lineTo(centerX, maxY + size4);
            context.closePath();
            context.stroke();

            context.strokeStyle = "red"
            context.beginPath();
            context.moveTo(ctr.heart_x_begin_left, ctr.heart_y_begin_left);
            context.lineTo(centerX, ctr.heart_y_begin_left);
            context.closePath();
            context.stroke();

            context.beginPath();
            context.moveTo(centerX, ctr.heart_y_end_right);
            context.lineTo(ctr.heart_x_end_right, ctr.heart_y_end_right);
            context.closePath();
            context.stroke();

            if (!onlyImg) {
                // ------------------------------
                // 绿色左
                context.beginPath();
                context.arc(ctr.lung_x_begin, ctr.lung_y, size3 * 4, 0, 2 * Math.PI);
                context.closePath();
                context.lineWidth = size3;
                context.strokeStyle = '#ffffff';
                context.stroke();
                // 添加路径
                path = new Path2D();
                path.arc(ctr.lung_x_begin, ctr.lung_y, size3 * 4, 0, 2 * Math.PI);
                paths.push({
                    type: 'line',
                    cursor: 'e-resize',
                    dir: 'x',
                    path: path,
                    key: 'lung_x_begin'
                });
                // 绿色右
                context.beginPath();
                context.arc(ctr.lung_x_end, ctr.lung_y, size3 * 4, 0, 2 * Math.PI);
                context.closePath();
                context.lineWidth = size3;
                context.strokeStyle = '#ffffff';
                context.stroke();
                // 添加路径
                path = new Path2D();
                path.arc(ctr.lung_x_end, ctr.lung_y, size3 * 4, 0, 2 * Math.PI);
                paths.push({
                    type: 'line',
                    cursor: 'e-resize',
                    dir: 'x',
                    path: path,
                    key: 'lung_x_end'
                });
                // 绿色中
                context.beginPath();
                context.arc(ctr.lung_x_begin + (ctr.lung_x_end - ctr.lung_x_begin) / 2, ctr.lung_y, size3 * 4, 0, 2 * Math.PI);
                context.closePath();
                context.lineWidth = size3;
                context.strokeStyle = '#ffffff';
                context.stroke();
                // 添加路径
                path = new Path2D();
                path.arc(ctr.lung_x_begin + (ctr.lung_x_end - ctr.lung_x_begin) / 2, ctr.lung_y, size3 * 4, 0, 2 * Math.PI);
                paths.push({
                    type: 'line',
                    cursor: 'n-resize',
                    dir: 'y',
                    path: path,
                    key: 'lung_y'
                });


                // 红色左
                context.beginPath();
                context.arc(ctr.heart_x_begin_left, ctr.heart_y_begin_left, size3 * 4, 0, 2 * Math.PI);
                context.closePath();
                context.lineWidth = size3;
                context.strokeStyle = '#ffffff';
                context.stroke();
                // 添加路径
                path = new Path2D();
                path.arc(ctr.heart_x_begin_left, ctr.heart_y_begin_left, size3 * 4, 0, 2 * Math.PI);
                paths.push({
                    type: 'line',
                    cursor: 'e-resize',
                    dir: 'x',
                    path: path,
                    key: 'heart_x_begin_left'
                });
                // 红色中
                context.beginPath();
                context.arc(ctr.heart_x_begin_left + (centerX - ctr.heart_x_begin_left) / 2, ctr.heart_y_begin_left, size3 * 4, 0, 2 * Math.PI);
                context.closePath();
                context.lineWidth = size3;
                context.strokeStyle = '#ffffff';
                context.stroke();
                // 添加路径
                path = new Path2D();
                path.arc(ctr.heart_x_begin_left + (centerX - ctr.heart_x_begin_left) / 2, ctr.heart_y_begin_left, size3 * 4, 0, 2 * Math.PI);
                paths.push({
                    type: 'line',
                    cursor: 'n-resize',
                    dir: 'y',
                    path: path,
                    key: 'heart_y_begin_left'
                });

                // 红色右
                context.beginPath();
                context.arc(ctr.heart_x_end_right, ctr.heart_y_end_right, size3 * 4, 0, 2 * Math.PI);
                context.closePath();
                context.lineWidth = size3;
                context.strokeStyle = '#ffffff';
                context.stroke();
                // 添加路径
                path = new Path2D();
                path.arc(ctr.heart_x_end_right, ctr.heart_y_end_right, size3 * 4, 0, 2 * Math.PI);
                paths.push({
                    type: 'line',
                    cursor: 'e-resize',
                    dir: 'x',
                    path: path,
                    key: 'heart_x_end_right'
                });
                // 红色中
                context.beginPath();
                context.arc(centerX + (ctr.heart_x_end_right - centerX) / 2, ctr.heart_y_end_right, size3 * 4, 0, 2 * Math.PI);
                context.closePath();
                context.lineWidth = size3;
                context.strokeStyle = '#ffffff';
                context.stroke();
                // 添加路径
                path = new Path2D();
                path.arc(centerX + (ctr.heart_x_end_right - centerX) / 2, ctr.heart_y_end_right, size3 * 4, 0, 2 * Math.PI);
                paths.push({
                    type: 'line',
                    cursor: 'n-resize',
                    dir: 'y',
                    path: path,
                    key: 'heart_y_end_right'
                });
            }
            this.paths.push(...paths.reverse());
        },

        // 画矩形
        drawRect(data, onlyImg) {
            var list = data;
            var context = this.context;
            var paths = [];

            var path = null;

            for (var i = 0; i < list.length; i++) {
                var item = list[i];
                if (item.isDelete) {
                    continue;
                }
                if (!item.mark) {
                    continue;
                }
                var confidence = item.confidence;
                var label = item.name;
                var color = config[label] || 'rgb(0,0,0)';

                if (confidence !== 1) {
                    label = label + " " + confidence;
                }
                var xmin = item.xmin + this.image.leftDis;
                var ymin = item.ymin + this.image.topDis;
                var xmax = item.xmax + this.image.leftDis;
                var ymax = item.ymax + this.image.topDis;

                var size1 = 60;
                var size2 = 8;
                var size3 = 4;

                context.fillStyle = color;
                context.strokeStyle = color;
                context.lineWidth = size2;
                context.font = size1 + "px 微软雅黑"
                context.beginPath();
                context.moveTo(xmin, ymin);
                context.lineTo(xmin, ymax);
                context.lineTo(xmax, ymax);
                context.lineTo(xmax, ymin);
                context.lineTo(xmin, ymin);
                context.fillText(label, xmin, ymin - 1)
                context.fillRect(xmin, ymin - size1, context.measureText(label).width, size1);
                context.closePath();
                context.stroke();
                context.fillStyle = "white"
                context.fillText(label, xmin, ymin - 1);

                if (!onlyImg) {
                    if (this.editRectIndex == i) {
                        // 添加左上
                        context.beginPath();
                        context.arc(xmin, ymin, size2 * 2, 0, 2 * Math.PI);
                        context.closePath();
                        context.lineWidth = size2;
                        context.strokeStyle = '#ffffff';
                        context.stroke();
                        // 添加路径
                        path = new Path2D();
                        path.arc(xmin, ymin, size2 * 2, 0, 2 * Math.PI);
                        paths.push({
                            type: 'rect',
                            cursor: 'nw-resize',
                            dir: 'xy',
                            path: path,
                            key: ['xmin', 'ymin'],
                            index: i
                        });

                        // 添加左下
                        context.beginPath();
                        context.arc(xmin, ymax, size2 * 2, 0, 2 * Math.PI);
                        context.closePath();
                        context.lineWidth = size2;
                        context.strokeStyle = '#ffffff';
                        context.stroke();
                        // 添加路径
                        path = new Path2D();
                        path.arc(xmin, ymax, size2 * 2, 0, 2 * Math.PI);
                        paths.push({
                            type: 'rect',
                            cursor: 'sw-resize',
                            dir: 'xy',
                            path: path,
                            key: ['xmin', 'ymax'],
                            index: i
                        });

                        // 添加右上
                        context.beginPath();
                        context.arc(xmax, ymin, size2 * 2, 0, 2 * Math.PI);
                        context.closePath();
                        context.lineWidth = size2;
                        context.strokeStyle = '#ffffff';
                        context.stroke();
                        // 添加路径
                        path = new Path2D();
                        path.arc(xmax, ymin, size2 * 2, 0, 2 * Math.PI);
                        paths.push({
                            type: 'rect',
                            cursor: 'ne-resize',
                            dir: 'xy',
                            path: path,
                            key: ['xmax', 'ymin'],
                            index: i
                        });

                        // 添加右下
                        context.beginPath();
                        context.arc(xmax, ymax, size2 * 2, 0, 2 * Math.PI);
                        context.closePath();
                        context.lineWidth = size2;
                        context.strokeStyle = '#ffffff';
                        context.stroke();
                        // 添加路径
                        path = new Path2D();
                        path.arc(xmax, ymax, size2 * 2, 0, 2 * Math.PI);
                        paths.push({
                            type: 'rect',
                            cursor: 'se-resize',
                            dir: 'xy',
                            path: path,
                            key: ['xmax', 'ymax'],
                            index: i
                        });
                    }

                    let xysize = 24;

                    // 添加中心
                    var xcenter = xmin + (xmax - xmin) / 2;
                    var ycenter = ymin + (ymax - ymin) / 2;
                    context.beginPath();
                    context.moveTo(xcenter - xysize, ycenter);
                    context.lineTo(xcenter + xysize, ycenter);
                    context.closePath();
                    context.lineWidth = size2 / 2;
                    context.strokeStyle = '#ffffff';
                    context.stroke();
                    context.beginPath();
                    context.moveTo(xcenter, ycenter - xysize);
                    context.lineTo(xcenter, ycenter + xysize);
                    context.closePath();
                    context.lineWidth = size2 / 2;
                    context.strokeStyle = '#ffffff';
                    context.stroke();
                    //添加路径
                    path = new Path2D();
                    path.rect(xcenter - xysize, ycenter - xysize, xysize * 2, xysize * 2);
                    paths.push({
                        type: 'rect',
                        cursor: this.editRectIndex == i ? 'move' : 'pointer',
                        dir: 'xy',
                        path: path,
                        index: i
                    });
                }
            }
            this.paths.push(...paths.reverse());
        },

        // 画添加矩形
        drawAddRect() {
            let xmin = this.add.xmin;
            let ymin = this.add.ymin;
            let xmax = this.add.xmax;
            let ymax = this.add.ymax;

            let label = this.add.name;
            let color = config[label] || 'rgb(0,0,0)';
            let context = this.context;

            var size1 = 60;
            var size2 = 8;
            var size3 = 4;

            context.fillStyle = color;
            context.strokeStyle = color;
            context.lineWidth = size2;
            context.font = size1 + "px 微软雅黑"
            context.beginPath();
            context.moveTo(xmin, ymin);
            context.lineTo(xmin, ymax);
            context.lineTo(xmax, ymax);
            context.lineTo(xmax, ymin);
            context.lineTo(xmin, ymin);
            context.fillText(label, xmin, ymin - 1)
            context.fillRect(xmin, ymin - size1, context.measureText(label).width, size1);
            context.closePath();
            context.stroke();
            context.fillStyle = "white"
            context.fillText(label, xmin, ymin - 1);
        },

        // 获取图片
        getImageFile(data) {
            this.showLine = true; // 是否显示线
            this.oldData = JSON.parse(JSON.stringify(data));
            this.newData = JSON.parse(JSON.stringify(data));

            this.drawData();

            // 保存图片
            var base64 = this.oCanvas.toDataURL('image/png');
            return base64ToFile(base64, '数据.png');
        }
    }


    const waitTimeout = function(time) {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve();
            }, time);
        })
    }
    </script>
</body>

</html>